NLP and skill extraction
The NLP and skill extraction subsystem powering resume analysis, structured data extraction, and predictive capabilities.
- Document ingestion and preprocessing
- Structured extraction via LLM prompts aligned to Pydantic schemas
- JSON validation and normalization
- Career path prediction and skill gap analysis using trained scikit-learn models
- TF-IDF vectorization for text similarity
- Model versioning, fallback strategies, and performance optimization
Repository layout#
The NLP subsystem spans three primary layers:
- Routes: Expose endpoints for resume analysis and detailed extraction
- Services: Orchestrate document processing, LLM calls, and schema validation
- Prompts and Models: Define extraction schemas, prompts, and ML assets
graph TB subgraph "Routes" R1["/resume/analysis"] R2["/resume/comprehensive/analysis/"] R3["/resume/format-and-analyze"] R4["/resume/analysis (v2)"] end subgraph "Services" S1["analyze_resume_service"] S2["comprehensive_resume_analysis_service"] S3["format_and_analyze_resume_service"] S4["analyze_resume_v2_service"] P1["process_document<br/>_convert_document_to_markdown<br/>_fallback_convert_to_text"] end subgraph "Prompts" PR1["JSON Extractor Prompt"] PR2["Comprehensive Analysis Prompt"] PR3["ATS Analysis Prompt"] end subgraph "Models" M1["best_model.pkl"] M2["tfidf.pkl"] end R1 --> S1 R2 --> S2 R3 --> S3 R4 --> S4 S1 --> P1 S2 --> PR2 S3 --> PR2 S4 --> PR2 PR1 --> M1 PR2 --> M1 PR3 --> M2
Building blocks#
- Document processing and fallback conversion for PDFs and office documents
- Structured extraction using Pydantic-aligned prompts
- JSON normalization and validation
- Career path prediction and skill gap analysis using trained scikit-learn models
- TF-IDF vectorization for text similarity
- Schema-driven outputs for work experience, education, projects, skills, and more
How it fits together#
Flow from upload to structured output and predictions:
sequenceDiagram participant Client as "Client" participant Route as "FastAPI Routes" participant Service as "Resume Analysis Services" participant Proc as "Document Processor" participant LLM as "LLM Provider" participant Schema as "Pydantic Schemas" Client->>Route : Upload resume Route->>Service : analyze_resume_service(file, llm) Service->>Proc : process_document(bytes, filename) Proc-->>Service : text/markdown/plain text alt Not plain text Service->>LLM : format_resume_text_with_llm(text) LLM-->>Service : cleaned text end Service->>Schema : Validate ResumeAnalysis Schema-->>Service : ResumeAnalysis model Service-->>Client : ResumeUploadResponse
Document processing and fallback conversion#
- Converts TXT/MD/PDF/DOCX to plain text/markdown
- Uses PyMuPDF and pymupdf4llm for parsing
- Falls back to Google GenAI multimodal conversion when PDF parsing fails and provider is Google/Gemini
flowchart TD
Start(["Start"]) --> Detect["Detect file extension"]
Detect --> IsText{"TXT/MD?"}
IsText --> |Yes| ReturnText["Return raw text"]
IsText --> |No| IsDoc{"PDF/DOC/DOCX?"}
IsDoc --> |No| Error["Unsupported type"]
IsDoc --> |Yes| Parse["Convert to Markdown"]
Parse --> Empty{"Empty output?"}
Empty --> |Yes| Fallback["Google GenAI fallback"]
Empty --> |No| Done(["Done"])
Fallback --> Done
Error --> End(["End"])
Done --> EndStructured extraction with Pydantic schemas#
- Detailed analysis prompt defines a rich schema covering skills, work experience, projects, education, certifications, achievements, languages, and metadata
- JSON extractor prompt normalizes raw LLM outputs to a strict schema with validation rules
- Both prompts are constructed as LangChain PromptTemplates and chained to the LLM
Key schema highlights:
- ComprehensiveAnalysisData: Top-level container for all extracted sections
- SkillProficiency: Skill name and inferred proficiency percentage
- UIDetailedWorkExperienceEntry: Role, company_and_duration, bullet points
- UIProjectEntry: Title, technologies_used, links, description
- EducationEntry, UICertificationEntry, UIPositionOfResponsibilityEntry, UIPublicationEntry, UIAchievementEntry: Standardized entries
- ResumeAnalysis: Legacy schema for normalized JSON extraction
classDiagram
class ComprehensiveAnalysisData {
+SkillProficiency[] skills_analysis
+str[] recommended_roles
+LanguageEntry[] languages
+EducationEntry[] education
+UIDetailedWorkExperienceEntry[] work_experience
+UIProjectEntry[] projects
+UIPublicationEntry[] publications
+UIPositionOfResponsibilityEntry[] positions_of_responsibility
+UICertificationEntry[] certifications
+UIAchievementEntry[] achievements
+str name
+str email
+str contact
+str linkedin
+str github
+str blog
+str portfolio
+str predicted_field
}
class SkillProficiency {
+str skill_name
+int percentage
}
class UIDetailedWorkExperienceEntry {
+str role
+str company_and_duration
+str[] bullet_points
}
class UIProjectEntry {
+str title
+str[] technologies_used
+str live_link
+str repo_link
+str description
}
class ResumeAnalysis {
+str name
+str email
+str linkedin
+str github
+str blog
+str portfolio
+str contact
+str predicted_field
+str college
+WorkExperienceEntry[] work_experience
+ProjectEntry[] projects
+str[] skills
+datetime upload_date
}
ComprehensiveAnalysisData --> SkillProficiency
ComprehensiveAnalysisData --> UIDetailedWorkExperienceEntry
ComprehensiveAnalysisData --> UIProjectEntryCareer path prediction and skill gap analysis#
- Trained scikit-learn model (GradientBoostingClassifier) stored as best_model.pkl
- Used to predict candidate roles and assist in skill gap analysis
- Typical workflow:
- Extract skills and normalize to canonical list
- Vectorize with TF-IDF (tfidf.pkl)
- Predict role/category and compute similarity scores
- Generate recommendations for missing skills
flowchart TD A["Extract skills<br/>Normalize to canonical list"] --> B["TF-IDF vectorization"] B --> C["Predict role/category<br/>(best_model.pkl)"] C --> D["Compute similarity scores"] D --> E["Generate skill gap report"] E --> F["Recommend remediation actions"]
TF-IDF vectorization and similarity#
- TF-IDF vectors enable semantic similarity comparisons between candidate profiles and job descriptions
- Used alongside trained classifier for detailed scoring and recommendations
Skill catalog and normalization#
- Canonical skill list maintained centrally for consistent extraction and matching
- Supports normalization and enrichment during analysis
API endpoints and workflows#
- File-based analysis: Upload resume, preprocess, clean, validate, and return structured data
- Detailed analysis: Full extraction pipeline with rich schema alignment
- Text-based analysis: Accept preformatted text and run detailed extraction
- Validation catches malformed inputs
sequenceDiagram participant Client as "Client" participant Route as "Routes" participant Service as "Services" participant LLM as "LLM" participant Schema as "Schemas" Client->>Route : POST /resume/comprehensive/analysis/ Route->>Service : comprehensive_resume_analysis_service(file, llm) Service->>LLM : comprehensive_analysis_llm(text, llm) LLM-->>Service : dict (ComprehensiveAnalysisData) Service->>Schema : ComprehensiveAnalysisData(**dict) Schema-->>Service : validated model Service-->>Client : ComprehensiveAnalysisResponse
Dependencies#
- Routes depend on services for orchestration
- Services depend on:
- Document processor for text extraction
- LLM chains for structured extraction
- Pydantic schemas for validation
- ML assets (best_model.pkl, tfidf.pkl) for predictions and similarity
- Prompts define the contract between unstructured text and structured outputs
graph LR Routes["Routes"] --> Services["Services"] Services --> Processor["Document Processor"] Services --> Prompts["Prompt Templates"] Services --> Schemas["Pydantic Schemas"] Prompts --> LLM["LLM Provider"] Services --> Models["ML Models<br/>best_model.pkl<br/>tfidf.pkl"]
Performance#
- Prefer plain text or markdown inputs to avoid heavy parsing overhead
- Cache TF-IDF vectors and model predictions where feasible
- Use streaming or chunked processing for long documents
- Monitor LLM latency and apply retry/backoff strategies
- Validate early to reduce downstream processing costs
Troubleshooting#
Common issues:
- Unsupported file type: Ensure TXT/MD/PDF/DOCX; check extension handling
- Empty or unreadable PDF: Trigger fallback conversion if provider supports it
- LLM errors: Validate API keys and provider configuration; confirm the model is available
- Schema validation failures: Review prompt instructions and refine extraction logic
- Missing predictions: Verify model and vectorizer files are present and loadable
Operational checks:
- Confirm GOOGLE_API_KEY and provider settings for fallback conversion
- Validate Pydantic schema compliance for extracted data
- Test TF-IDF and model loading independently